/******************************************************************************* 
  Copyright (C), 1988-2020, zeno Tech. Co., Ltd.
  Description:   AIN模块  
  Function List:     
  History:
    <wyg -- 2023-03-29>  创建
*******************************************************************************/ 

/*=============================================================================
                                 Includes                                  
 =============================================================================*/
#ifdef CONNECT_CORE
#define _GNU_SOURCE
#include <sched.h>
#include <pthread.h>
#endif
#include "audioPriv.h"
#include "StreamComposeMgr.h"
#include <signal.h>
#include <sys/time.h>
#include "awi_audiomix_constant.h"
#include "awi_audiomix_cfg.h"
#include "awi_audiomix_process.h"
/*=============================================================================
                               Macro Definition
 =============================================================================*/
#define AMIX_OUT_NUM  MAX_INTERFACE_NUM

#define AMIX_LINEOUT_CHN (MAX_INTERFACE_NUM - 1)

#define BGM_FUNC
/*=============================================================================
                        Local Structures and Typedef 
 =============================================================================*/

/*=============================================================================
                             Extern Variables                                  
=============================================================================*/
extern unsigned long long vdo_get_time();
extern int ADEC_GetFullFromList(ADEC_ctl_t *pAdecCtl, ACOMM_listInfo_t* pListPacket);
extern int ADEC_PutEmptyToList(ADEC_ctl_t *pAdecCtl, ACOMM_listInfo_t* pListPacket);
extern int AI_GetFullFromList(AI_ctl_t *pAiCtl, ACOMM_listInfo_t* pListPacket);
extern int AI_PutEmptyToList(AI_ctl_t *pAiCtl, ACOMM_listInfo_t* pListPacket);

extern const int Dymic_Mirror_Num;

/*=============================================================================
                             Local Variables                                  
 =============================================================================*/
static pthread_t    dataComposeThd_s[AMIX_OUT_NUM];

static pthread_t    dataPrepareThd_s;


static pthread_t    lineoutPrepareThd_s;

static pthread_t    lineoutThd_s;

static pthread_t    composeCheckThd_s;

// 延时初始化
static long long _tick[AMIX_OUT_NUM] = {0}; 
static long long _tickErr[AMIX_OUT_NUM] = {0};

/*=============================================================================
                             Function Definition                                  
 =============================================================================*/ 
static __inline unsigned long long GetMicroTickCount()
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ((unsigned long long)ts.tv_sec * 1000000L + ts.tv_nsec / 1000);
}

static unsigned long long GetMicroTime()
{
    return GetMicroTickCount();/* us */
}

static void DelayUs(long int us)
{
    struct timeval tv;
    tv.tv_sec = us / 1000000;
    tv.tv_usec = us % 1000000;
    select(0, NULL, NULL, NULL, &tv);
}

// 每次延时一半时差,直至延时满us或差值小于err,注意要放在循环开始
static void AMIX_PreciseDelay(StreamOutInterface index, long long us, long long err)
{
    if(index < AMIX_OUT_NUM)                
    {
        do
        {        
            _tickErr[index] = GetMicroTime() - _tick[index];    
            if (_tickErr[index] > 0 && us > _tickErr[index]) 
            {                                  
                _tickErr[index] = us - _tickErr[index];      
                if (_tickErr[index] > err)            
                {                              
                    DelayUs(_tickErr[index] / 2);
                    continue;                  
                }                              
            }
            break;
        }while(1);
        _tick[index] = GetMicroTime();      
    } 
}


static int AMIX_IsBgmNeedPlay()
{
    PlayState state;
    getCurtainPlayState(&state);
    if(state != RUNNING)
    {
        return 0;
    }
    
    CurtainInfo curtainInfo;    
    memset(&curtainInfo, 0, sizeof(curtainInfo));    
    getCurtainLayout(&curtainInfo); //获取拼接布局
    int outNum = curtainInfo.outNum;
    if(outNum <= 0)
    {
        return 0;
    }

    int curtainNum = curtainInfo.curtainNum;
    if(curtainNum == Dymic_Mirror_Num)
    {
        return -1; //投屏时bgm不播放
    }

    StreamCofigInfo configInfo = {0};
    AudioMixerInfo audioMixerInfo = {0};
    
    for(int i = 0; i < outNum; ++i)
    {
        configInfo = curtainInfo.cofigInfo[i];
        if(configInfo.interface != HDMI_OUT && configInfo.interface != LINE_OUT) 
        {
            continue;
        }
        
        int totalInput = configInfo.audioMixerInfo.totalInput;
        if(totalInput > 0)
        {
            return -1; //HDMI_OUT或LINE_OUT有音频输出，bgm不播放
        }
    }

    return 0;
}


void AMIX_initBgmComposeBuf(AMIX_composeCtl_t* pComposeCtl)
{
    LOG_PrintInfo("AMIX_initBgmComposeBuf enter\n");
    

    int i = AMIX_LINEOUT_CHN;
    pthread_rwlock_wrlock(&pComposeCtl->decComposeBuf[i].rwLock);
    
    pComposeCtl->newPts[i] = 0;
    pComposeCtl->userNums[i] = 0;

    pComposeCtl->decComposeBuf[i].multiplexNums = 0;

    pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[i].rwLock);


    LOG_PrintInfo("AMIX_initBgmComposeBuf leave\n");
}


void AMIX_initDecComposeBuf(AMIX_composeCtl_t* pComposeCtl)
{
    LOG_PrintInfo("AMIX_initDecComposeBuf enter\n");
    int initMax = MAX_CHN_NUM_AMIX;

#ifdef BGM_FUNC    
    int bgmState = 0;
    getBgmCurtainState(&bgmState);
    if(bgmState == 0 && AMIX_IsBgmNeedPlay() == 0)
    {
        initMax = MAX_CHN_NUM_AMIX - 1;//bgm通道不在此处初始化
    }
#endif

    for(int i = 0; i < initMax; ++i)
    {
        pthread_rwlock_wrlock(&pComposeCtl->decComposeBuf[i].rwLock);
        
        pComposeCtl->newPts[i] = 0;
        pComposeCtl->userNums[i] = 0;

        pComposeCtl->decComposeBuf[i].multiplexNums = 0;

        pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[i].rwLock);
    }

    LOG_PrintInfo("AMIX_initDecComposeBuf leave\n");
}

/*******************************************************************************
    Function:     AI_PutPacketToList
    Description:  从外部输入音频数据
    Input:        - pThiz: 音频输入接口指针
    Output:       - packet：输入的音频数据指针
    Return:       0: 操作成功
                  -1: 操作失败
    Others:       无
*******************************************************************************/
int AMIX_GetStreamMultiplexNum(int displayChn, uint8 *multiplexNums)
{
    CurtainInfo curtainInfo = {0};
    StreamCofigInfo configInfo = {0};
    AudioMixerInfo audioMixerInfo = {0};
    StreamInfo stream = {0};
    int outNum = 0;
	int totalInput = 0;
	
	*multiplexNums = 0;

#ifdef BGM_FUNC   
    //LINEOUT输入流处理
	if(displayChn == AMIX_LINEOUT_CHN)
    {
        int bgmState = 0;
        getBgmCurtainState(&bgmState);
        if(bgmState == 0 && AMIX_IsBgmNeedPlay() == 0)
        {
            *multiplexNums = 1; //bgm处理
            return 0;
        }
    }
#endif	
    getCurtainLayout(&curtainInfo); //获取拼接布局
    outNum = curtainInfo.outNum;
    if(outNum <= 0)
    {
        return -1;
    }

    for(int i = 0; i < outNum; ++i)
    {
        configInfo = curtainInfo.cofigInfo[i];

        audioMixerInfo = configInfo.audioMixerInfo;
        totalInput = audioMixerInfo.totalInput;

        for(int j = 0; j < totalInput; ++j)
        {
            stream = audioMixerInfo.audioInfo[j].audioStream;

            if(displayChn == stream.displayChn)
            {
                *multiplexNums += 1;
            }
        }
    }

    return 0;
}
static int AMIX_SetNodeToList(int channel, AMIX_composeInfo_t* pNodeFrame)
{
    if (!pNodeFrame)
    {
        LOG_PrintInfo("pListFrame is NULL\n");
        return -1;
    }
    
    StreamInType type = pNodeFrame->streamType;
    if((type == RTSP_STREAM) || (type == VIDEOFILE_STREAM) || (type == ONLINEMP4_STREAM))
    {
        ADEC_ctl_t *pAdecCtl = audioCtl_g.pAdecCtls[channel];
        if (!pAdecCtl)
        {
            //LOG_PrintInfo("pDecCtl adecChn:%d is NULL\n",channel);
            return -1;
        }

        ///put node to list
        ADEC_PutEmptyToList(pAdecCtl, &pNodeFrame->listStreamFrame);     


        //LOG_PrintInfo("AMIX_SetNodeToList:: bufLen=%d\n",pNodeFrame->listStreamFrame.len);
    }
    else
    {
        AI_ctl_t * pAiCtl = audioCtl_g.pAiCtls[channel];
        if (!pAiCtl)
        {
            //LOG_PrintInfo("pAiCtl aiChn:%d is NULL\n",channel);
            return -1;
        }

        ///put node to list
        AI_PutEmptyToList(pAiCtl, &pNodeFrame->listStreamFrame); 
    }

    //init
    pNodeFrame->storePts = 0;
    pNodeFrame->streamType = 0;
    pNodeFrame->multiplexNums = 0;

    return 0;
}


static int AMIX_GetNodeFromList(int channel, StreamInType type, AMIX_composeInfo_t* pNodeFrame)
{  
    int iRet = 0; 
    static long long cntTmp = 0;
    if((type == RTSP_STREAM) || (type == VIDEOFILE_STREAM) || (type == ONLINEMP4_STREAM))
    {
        ADEC_ctl_t * pDecCtl = audioCtl_g.pAdecCtls[channel];
        if (!pDecCtl)
        {
            //LOG_PrintInfo("pDecCtl aecChn:%d is NULL\n",channel);
            return -1;
        }

        ///get node from list
        iRet = ADEC_GetFullFromList(pDecCtl, &pNodeFrame->listStreamFrame);
        if(iRet)
        {    
            //LOG_PrintInfo("ADEC_GetFullFromList failed\n");
            return -1;
        }

       //audio_FILE_Write("wyg/audio_dec2.pcm", pNodeFrame->listStreamFrame.pBuf, pNodeFrame->listStreamFrame.len); 
        

    #if 0
        if(cntTmp++ % 1 == 0)
        {
            LOG_PrintInfo("AMIX_GetNodeFromList:: bufLen=%d, listStreamFrame.pts=%llu\n",pNodeFrame->listStreamFrame.len, pNodeFrame->listStreamFrame.pts);
        }
    #endif
    }
    else
    {
        AI_ctl_t * pAiCtl = audioCtl_g.pAiCtls[channel];
        if (!pAiCtl)
        {
            //LOG_PrintInfo("pDecCtl aecChn:%d is NULL\n",channel);
            return -1;
        }

        ///get node from list
        iRet = AI_GetFullFromList(pAiCtl, &pNodeFrame->listStreamFrame);
        if(iRet)
        {    
            //LOG_PrintInfo("AI_GetFullFromList failed\n");
            return -1;
        }
    } 

    pNodeFrame->storePts = pNodeFrame->listStreamFrame.pts;     
    pNodeFrame->streamType = type;

    AMIX_GetStreamMultiplexNum(channel, &pNodeFrame->multiplexNums);

    //LOG_PrintInfo("channel:%d,type:%d, multiplexNums=%d, storepts=%llu\n",channel, type, pNodeFrame->multiplexNums, pNodeFrame->storePts);

    return iRet;
}

#if 1
static void *AMIX_LineoutPrepareThd(void *parg)
{
    AMIX_composeCtl_t* pComposeCtl = (AMIX_composeCtl_t*)parg;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return NULL;
    }

    prctl(PR_SET_NAME, __func__);
    LOG_PrintInfo("tid:%d\n", gettid());

    int iRet = 0;
    AMIX_composeInfo_t* pMixListFrame = NULL;      
    StreamInfo streamInfo[16];
    int streamNum = 0;
    StreamInType type = INSIDE_STREAM;
    int streamIndex = 0;

    int isStreamUpdte = 0;
    int state = 0;    
    int playState = 0;
 
    while(1)
    {
        /* get state */        
        getBgmCurtainState(&state);
        if(state != 0 || AMIX_IsBgmNeedPlay())
        {            
            if(playState == 0)
            {
                playState = -1;
                AMIX_initBgmComposeBuf(pComposeCtl);
            }
            usleep(50*1000);
            continue;
        }
        playState = 0;
        
        streamIndex = AMIX_LINEOUT_CHN;        

        int iRet = pthread_rwlock_trywrlock(&pComposeCtl->decComposeBuf[streamIndex].rwLock);//加写锁
        if(iRet != 0)
        {
            usleep(1*1000);
            continue;
        }

        isStreamUpdte = 0;
        type = VIDEOFILE_STREAM;
        pMixListFrame = &pComposeCtl->decComposeBuf[streamIndex];
        
        if( (pComposeCtl->newPts[streamIndex] > pMixListFrame->storePts)
        && (pComposeCtl->userNums[streamIndex] >= pMixListFrame->multiplexNums) )//有最新流需要更新,重新拉流可能会处理上一次遗留的几帧数据
        {
            if(pMixListFrame->storePts > 0)
            AMIX_SetNodeToList(streamIndex, pMixListFrame);               
            
            iRet = AMIX_GetNodeFromList(streamIndex, type, pMixListFrame);
            if(iRet < 0)
            {
                //LOG_PrintWarn("AMIX_GetNodeFromList return\n");
                pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[streamIndex].rwLock);//异常退出及时关闭锁
                usleep(1*1000);
                continue;
            }

            //audio_FILE_Write3("/nfsroot/StreamFile/test/audio_prepare_out.pcm", pMixListFrame->listStreamFrame.pBuf, pMixListFrame->listStreamFrame.len);  
            
            pComposeCtl->userNums[streamIndex] = 0;
            isStreamUpdte = 1;
        } 

        pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[streamIndex].rwLock);     

        usleep(5000);
    }
     
    return NULL;
}
#endif

static void * AMIX_ComposeCheckThd(void* arg){
    AMIX_composeCtl_t* pComposeCtl = audioCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
       LOG_PrintInfo("pComposeCtl is NULL\n");
       return;
    }
    CurtainInfo curtainInfo = {0};
    StreamCofigInfo configInfo = {0};
    PlayState state = IDLE;
    PlayState last_state = IDLE;

    while(1){
        memset(&curtainInfo, 0, sizeof(curtainInfo));
        getCurtainLayout(&curtainInfo); //获取拼接布局
        getCurtainPlayState(&state);
        if(state == last_state){
            usleep(50000);
            continue;
        }

        last_state = state;
        if(curtainInfo.outNum <= 0 || state != RUNNING)
        {
            for(int i = 0; i < MAX_CHN_NUM_AMIX; ++i){
                pthread_mutex_lock(&pComposeCtl->mutex_run[i]);
                pComposeCtl->running[i] = 0;
                pthread_mutex_unlock(&pComposeCtl->mutex_run[i]);
            }
            usleep(50000);
            continue;
        }
        
        for(int i = 0; i < curtainInfo.outNum; ++i)
        {
            configInfo = curtainInfo.cofigInfo[i];
            pthread_mutex_lock(&pComposeCtl->mutex_run[configInfo.interface]);
            pthread_cond_signal(&pComposeCtl->cond_run[configInfo.interface]);
            pComposeCtl->running[configInfo.interface] = 1;
            pthread_mutex_unlock(&pComposeCtl->mutex_run[configInfo.interface]);
        }
        usleep(30*1000);
    }
    return NULL;
}

static void *AMIX_DataPrepareThd(void *parg)
{
    AMIX_composeCtl_t* pComposeCtl = (AMIX_composeCtl_t*)parg;
    if (!pComposeCtl)
    {
        LOG_PrintInfo("pComposeCtl is NULL\n");
        return NULL;
    }

    prctl(PR_SET_NAME, __func__);
    LOG_PrintInfo("tid:%d\n", gettid());

    int iRet = 0;
    AMIX_composeInfo_t* pMixListFrame = NULL;      
    StreamInfo streamInfo[16];
    int streamNum = 0;
    StreamInType type = INSIDE_STREAM;
    int streamIndex = 0;

    int isStreamUpdte = 0;
    PlayState state = IDLE;
    PlayState lastState = IDLE;
 
    while(1)
    {
        streamNum = 0;
        getStreamInfo(1, streamInfo, &streamNum);
        if(streamNum <= 0 || streamNum > MAX_STREAM_NUM)
        {
            usleep(10*1000);
            continue;
        }

        getCurtainPlayState(&state);
        if(state != RUNNING)
        {
            if(lastState == RUNNING)
            {
                lastState = state;
                AMIX_initDecComposeBuf(pComposeCtl);
            }
            usleep(5*1000);
            continue;
        }
        lastState = state;         
        
        isStreamUpdte = 0;
        for(int i = 0; i < streamNum; ++i)
        {
            streamIndex = streamInfo[i].displayChn;
            
            type = streamInfo[streamIndex].type;

            int iRet = pthread_rwlock_trywrlock(&pComposeCtl->decComposeBuf[streamIndex].rwLock);//加写锁
            if(iRet != 0)
            {
                continue;
            }
            
            pMixListFrame = &pComposeCtl->decComposeBuf[streamIndex];
            
            if( (pComposeCtl->newPts[streamIndex] > pMixListFrame->storePts)
            && (pComposeCtl->userNums[streamIndex] >= pMixListFrame->multiplexNums) )//有最新流需要更新,重新拉流可能会处理上一次遗留的几帧数据
            {
                //
                if(pMixListFrame->storePts > 0)
                AMIX_SetNodeToList(streamIndex, pMixListFrame);               
                
                iRet = AMIX_GetNodeFromList(streamIndex, type, pMixListFrame);
                if(iRet < 0)
                {
                    pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[streamIndex].rwLock);//异常退出及时关闭锁
                    continue;
                }
                
                pComposeCtl->userNums[streamIndex] = 0;
                isStreamUpdte = 1;                
            } 
            /*else if(i == 0)
            {
                LOG_PrintInfo("newPts[%d]=%llu, storePts=%llu, userNums=%d, multiplexNums=%d\n", 
                    streamIndex, pComposeCtl->newPts[streamIndex], pMixListFrame->storePts,
                    pComposeCtl->userNums[streamIndex], pMixListFrame->multiplexNums);
            }*/

            pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[streamIndex].rwLock);
        }        

        usleep(500);
    }
     
    return NULL;
}

static int AMIX_DoResampler(SpeexResamplerState *resampler, int sampleRate, char *inputData, uint *inputLen, char *outputData, uint *outputLen)
{
    if(!inputData || !outputData)
    {
        LOG_PrintError("Input params error\n");
        return -1;
    }
    
    uint dealLen = *inputLen / 2;
       
    if(resampler) 
    {
        AUDIO_GetOutSamples(sampleRate, outputLen);
                    
        speex_resampler_process_int(resampler, 0, (short*)inputData, &dealLen, (short*)outputData, outputLen);

        *outputLen = (*outputLen) * 2;    
    }

    return 0;
}

static void*AMIX_LineoutDealThd(void *parg)
{    
    AMIX_composeCtl_t* pComposeCtl = audioCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
       LOG_PrintInfo("pComposeCtl is NULL\n");
       return NULL;
    }

    prctl(PR_SET_NAME, __func__);
    LOG_PrintInfo("AMIX_LineoutDealThd tid:%d\n", gettid());
    ACOMM_listInfo_t* pListFrame = NULL;
    int state = 0;
    uint64 lastFramPts = 0;

    int sampleRate = 48000;
	int channelNum = 4;
	int lastSampleRate = 0;
	int lastChannelNum = 0;
	int displayChn = 0;
	long long printCnt= 0;
	int quickRef = 100;

	audiomix_cfg_t cfg_mixer;
	awi_audiomix_cfg_init(&cfg_mixer);
	char inputFrame1[MAX_PCM_SIZE] = {0};	
	char dualTrackData[MAX_PCM_SIZE] = {0};
	char *outputFrame = NULL;
	uint inputLen = 0;
	uint outputLen = 0;
	
	AudioOutput *pAudioOutput = NULL;
	uint8 waitTimeFlg = 0;
	int ret = 0;
	unsigned long long ts = 0;
    unsigned long long  runtime = 0;
    uint8 lastWaitTimeFlg = 0;
    uint16 noChangeCnt = 0;

    StreamOutInterface interface = LINE_OUT;
    
    while(1)
    { 
        if(waitTimeFlg == 0)
        {
            AMIX_PreciseDelay(interface,15000, 1); //15ms
        }
        else if(waitTimeFlg == 1)
        {
            AMIX_PreciseDelay(interface,1000, 1); //1ms
        }
        else if(waitTimeFlg == 2)
        {
            AMIX_PreciseDelay(interface,50000, 1); //50ms
        }
        else if(waitTimeFlg == 3)
        {
            AMIX_PreciseDelay(interface,15950, 1); //15.95ms //时间长会报underrun错误，时间短会导致音频延迟
        }
        else if(waitTimeFlg == 4)
        {
            AMIX_PreciseDelay(interface,100, 1); //100us
        }
                
        /* get state */        
        getBgmCurtainState(&state);
        if(state < 0 || AMIX_IsBgmNeedPlay())
        {
            //LOG_PrintWarn("state: %d\n", state);
             waitTimeFlg = 2;
            continue;
        }

        /* get data */      
        memset(inputFrame1, 0, MAX_PCM_SIZE);
        quickRef = 100;
        displayChn = AMIX_LINEOUT_CHN;
        waitTimeFlg = 0;
        
        pthread_rwlock_rdlock(&pComposeCtl->decComposeBuf[displayChn].rwLock); //加读锁
       
        pListFrame = &pComposeCtl->decComposeBuf[displayChn].listStreamFrame;

        if((pListFrame->pts == 0) || (pComposeCtl->decComposeBuf[displayChn].storePts == 0) || (pComposeCtl->newPts[displayChn] == 0))
        {
            pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[displayChn].rwLock);   
            //LOG_PrintWarn("no data\n");
            continue;
        }
        
        if(pListFrame->pts == lastFramPts)
        {
            pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[displayChn].rwLock);
            //LOG_PrintWarn("Buf[%d]: recall pts=%llu, curpts=%llu\n",displayChn, pListFrame->pts, vdo_get_time());
            {
                if(noChangeCnt < quickRef) //连续noChangeCnt次没有更新数据延时恢复
                {
                    noChangeCnt++;
                    if(lastWaitTimeFlg == 0)
                    {
                        waitTimeFlg = 1;
                    }
                }
                else
                {  
                    if(lastWaitTimeFlg != waitTimeFlg)
                    {
                        lastWaitTimeFlg = waitTimeFlg;
                    }
                }
            }
            continue;
        }

        lastFramPts = pListFrame->pts;
        
        memcpy(inputFrame1, pListFrame->pBuf, pListFrame->len);
        inputLen = pListFrame->len;

        //audio_FILE_Write2("/nfsroot/StreamFile/test/audio_get_out.pcm", inputFrame1, inputLen);   

        pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[displayChn].rwLock);

        pthread_rwlock_wrlock(&pComposeCtl->decComposeBuf[displayChn].rwLock); //加写锁
        pComposeCtl->userNums[displayChn] += 1; 
        pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[displayChn].rwLock);
       
        lastWaitTimeFlg = waitTimeFlg;
        noChangeCnt = 0;
        outputFrame = inputFrame1;
        outputLen = inputLen;

        ///单声道变成双声道音频流
        if(channelNum == 2)
        {            
            for (int i = 0; i < outputLen; i+=2)
            { 
            	memcpy(dualTrackData + 2*i, outputFrame + i, 2);
            	memcpy(dualTrackData + 2*i + 2, outputFrame + i, 2);
            }

            outputFrame = dualTrackData;
            outputLen *= 2;
        }
        else if(channelNum == 4)
        { 
            int i = 0; int j = 0;
            for (i = 0, j = 0; j < outputLen; i += 4, j += 2)
            { 
            	memcpy(dualTrackData + 2*i, outputFrame + j, 2);
            	memcpy(dualTrackData + 2*i + 2, outputFrame + j, 2);
            	memcpy(dualTrackData + 2*i + 4, outputFrame + j, 2);
            	memcpy(dualTrackData + 2*i + 6, outputFrame + j, 2);
            }

            outputFrame = dualTrackData;
            outputLen *= channelNum;

            //audio_FILE_Write("wyg/audio_hdmiout.pcm", outputFrame, outputLen); 
        }

        ///音频输出对象创建
        if(!pAudioOutput)
        {
            AudioOutDesc outDesc = {0};
            outDesc.card = 0;
            outDesc.channel = 0; 
                                
            ret = createAudioOutput(&outDesc, &pAudioOutput);
            if(ret || !pAudioOutput)
            {
                LOG_PrintError("createAudioOutput failed\n");
                continue;
            }
        }

        ///采样率或通道数变化时更新输出参数
        if((lastSampleRate != sampleRate) 
            || (lastChannelNum != channelNum))
        {
            pAudioOutput->stop(pAudioOutput);
        
            AudioOutAttr format = {0};  
            ret = AUDIO_GetOutNode(interface, format.pcAudioNode); //todo
            if(ret)
            {
                LOG_PrintError("AUDIO_GetOutNode failed\n");
                continue;
            }

            printf("LINEOUT start pcAudioNode=%s, sampleRate=%d, channelNum=%d\n",format.pcAudioNode, sampleRate, channelNum);
            
    	    format.enSampleFormat = SAMPLE_FMT_S16;               	
        	format.u32SampleRate = sampleRate;
        	format.u32Channels = channelNum;

        	AUDIO_GetOutSamples(sampleRate, &format.u32NbSamples);

        	pAudioOutput->setChnAttr(pAudioOutput, format);
        	
            pAudioOutput->start(pAudioOutput);

            lastSampleRate = sampleRate;
            lastChannelNum = channelNum;
        }


        //audio_FILE_Write("/nfsroot/StreamFile/test/audio_data_out.pcm", outputFrame, outputLen);   

        //AO输出
        pAudioOutput->sendDataToAo(pAudioOutput, outputFrame, outputLen);

    }

     return NULL;    
}

static void *AMIX_DataComposeThd(void *parg)
{
    StreamOutInterface interface = USBTYPEC_OUT;
    memcpy(&interface, (StreamOutInterface*)parg, sizeof(StreamOutInterface));
    free(parg);
    //LOG_PrintInfo("Audio output interface=%d\n", interface);
    AMIX_composeCtl_t* pComposeCtl = audioCtl_g.pComposeCtl;
    if (!pComposeCtl)
    {
       LOG_PrintInfo("pComposeCtl is NULL\n");
       return NULL;
    }

    if(interface == RTSP_SUB_OUT1
        || interface == RTSP_SUB_OUT2
        || interface == RTSP_SUB_OUT3
        || interface == RTSP_SUB_OUT4
        || interface == RTSP_SUB_OUT5)
    {
        return NULL; //暂不处理，减少cpu占用
    }

//#ifdef BGM_FUNC  
#if 0
    if(interface == HDMI_OUT)
    {
        int bgmState = 0;
        getBgmCurtainState(&bgmState);
        if(bgmState == 0)
        {  
            return NULL; //bgm优先使用LINE_OUT
        }
        else
        {
            LOG_PrintWarn("getBgmCurtainState:%d\n", bgmState);
        }
    }
#endif

    prctl(PR_SET_NAME, __func__);
    //LOG_PrintInfo("tid:%d\n", gettid());
    ACOMM_listInfo_t* pListFrame = NULL;
    CurtainInfo curtainInfo = {0};
    StreamCofigInfo configInfo = {0};
    AudioMixerInfo audioMixerInfo = {0};
    StreamInfo stream = {0};
    int outNum = 0;
    PlayState state = IDLE;
    uint64 lastFramPts[MAX_CHN_NUM_AMIX] = {0};

    int sampleRate = 48000;
	int channelNum = 2;
	int lastSampleRate = 0;
	int lastChannelNum = 0;
	StreamInType type = INSIDE_STREAM;
	int displayChn = 0;
	static long long printCnt= 0;

	audiomix_cfg_t cfg_mixer;
	awi_audiomix_cfg_init(&cfg_mixer);
	char inputFrame1[MAX_PCM_SIZE] = {0};
	char inputFrame2[MAX_PCM_SIZE] = {0};
	char algFrame[MAX_PCM_SIZE] = {0};
	char dualTrackData[MAX_PCM_SIZE] = {0};
	
	char *outputFrame = NULL;
	uint8 dealNum = 0;
	uint inputLen = 0;
	uint inputLen2 = 0;
	uint outputLen = 0;
	uint algLen = 0;
	AudioOutput *pAudioOutput = NULL;
	uint8 waitTimeFlg = 0;
	int ret = 0;

	SpeexResamplerState *mixResampler = NULL;

	unsigned long long ts = 0;
    unsigned long long  runtime = 0;

    uint8 lastWaitTimeFlg = 0;
    uint16 noChangeCnt = 0;
    
    while(1)
    { 
        pthread_mutex_lock(&pComposeCtl->mutex_run[interface]);
        if(pComposeCtl->running[interface] == 0){
            struct timespec timeout;
            clock_gettime(CLOCK_REALTIME, &timeout);
            timeout.tv_sec += 2;

            if(pthread_cond_timedwait(&pComposeCtl->cond_run[configInfo.interface], 
                &pComposeCtl->mutex_run[interface], &timeout) != 0){
                pthread_mutex_unlock(&pComposeCtl->mutex_run[interface]);
                continue;
            }    
        }
        pthread_mutex_unlock(&pComposeCtl->mutex_run[interface]);
        if(waitTimeFlg == 0)
        {
            AMIX_PreciseDelay(interface,15000, 1); //15ms
        }
        else if(waitTimeFlg == 1)
        {
            AMIX_PreciseDelay(interface,1000, 1); //1ms
        }
        else if(waitTimeFlg == 2)
        {
            AMIX_PreciseDelay(interface,50000, 1); //50ms
        }
        else if(waitTimeFlg == 3)
        {
            {
                pthread_mutex_lock(&audioCtl_g.mutex_ai[interface]);

                while (audioCtl_g.sharedData_ai[interface] == 0) {
                    pthread_cond_wait(&audioCtl_g.cond_ai, &audioCtl_g.mutex_ai[interface]);
                }
                audioCtl_g.sharedData_ai[interface] = 0;
                
                pthread_mutex_unlock(&audioCtl_g.mutex_ai[interface]);
            }
            #if 0
            {
                AMIX_PreciseDelay(interface,15950, 1); //15.95ms //时间长会报underrun错误，时间短会导致音频延迟
            }
            #endif
        }
        else if(waitTimeFlg == 4)
        {
            AMIX_PreciseDelay(interface,500, 1); //500us
        }

        //ts = vdo_get_time();
    #if 0
        if(interface == HDMI_OUT)
        {
            int bgmState = 0;
            getBgmCurtainState(&bgmState);
            if(bgmState == 0)
            {  
                //LOG_PrintWarn("getBgmCurtainState:%d\n", bgmState);
                //break; //BGM优先，普通场景退出

                waitTimeFlg = 2;
                continue;
            }
        }
    #endif
        /* step1: get layout */        
        memset(&curtainInfo, 0, sizeof(curtainInfo));
        getCurtainLayout(&curtainInfo); //获取拼接布局
        outNum = curtainInfo.outNum;
        if(outNum <= 0)
        {
            //LOG_PrintError("pictureNum is error !\n");
            waitTimeFlg = 0;
            continue;
        }

        getCurtainPlayState(&state);
        if(state != RUNNING)
        {
            //LOG_PrintWarn("state: %d\n", state);
            waitTimeFlg = 0;
            continue;
        }
        
        memset(&configInfo, 0, sizeof(configInfo));
        memset(&audioMixerInfo, 0, sizeof(audioMixerInfo));
        waitTimeFlg = 2;
        dealNum = 0;
        int i = 0;
        for(i = 0; i < outNum; ++i)
        {
            configInfo = curtainInfo.cofigInfo[i];

            //LOG_PrintError("configInfo.interface is %d , interface:%d!\n", configInfo.interface,interface);
            if(configInfo.interface != interface) //每种输出对应一个拼接线程
            {
                continue;
            }

            waitTimeFlg = 0;
            audioMixerInfo = configInfo.audioMixerInfo;
            
            int totalInput = audioMixerInfo.totalInput;
            uint16 quickRef = 100; 
            if(totalInput <= 0)
            {
                continue;
            } 
            else if((totalInput > 1) && (lastWaitTimeFlg == 3))
            {
                quickRef = 1000;
            }

            //LOG_PrintError("interface is %d , totalInput:%d!\n", interface, totalInput);
            
            if((sampleRate != audioMixerInfo.sampleRate) && (audioMixerInfo.sampleRate > 0))
            {               
                sampleRate = audioMixerInfo.sampleRate;
            }
            if((channelNum != audioMixerInfo.channelNum) && (audioMixerInfo.channelNum > 0))
            {
                channelNum = audioMixerInfo.channelNum;
            }           

            memset(inputFrame1, 0, MAX_PCM_SIZE);
            memset(inputFrame2, 0, MAX_PCM_SIZE);
            memset(algFrame, 0, MAX_PCM_SIZE);
            dealNum = 0;

            for(int j = 0; j < totalInput; ++j)
            {
                stream = audioMixerInfo.audioInfo[j].audioStream;

                displayChn = stream.displayChn;
                if(displayChn >= MAX_STREAM_NUM)
                {
                    LOG_PrintError("displayChn is over !\n");
                    continue;
                }      

                //printf("interface is %d, displayChn %d\n", interface, displayChn);

                type = stream.type;
                if(type == INSIDE_STREAM)
                {
                    continue; // INSIDE_STREAM流不处理  
                }

                ///提取数据
                {
                    
                    pthread_rwlock_rdlock(&pComposeCtl->decComposeBuf[displayChn].rwLock); //加读锁
                   
                    pListFrame = &pComposeCtl->decComposeBuf[displayChn].listStreamFrame;

                    if((pListFrame->pts == 0) || (pComposeCtl->decComposeBuf[displayChn].storePts == 0) || (pComposeCtl->newPts[displayChn] == 0))
                    {
                        pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[displayChn].rwLock);                         
                        continue;
                    }

                    
                    if(pListFrame->pts == lastFramPts[displayChn])
                    {
                        pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[displayChn].rwLock);
                        //LOG_PrintWarn("Buf[%d]: recall pts=%llu, curpts=%llu\n",displayChn, pListFrame->pts, vdo_get_time());
                        if(curtainInfo.curtainNum != 98)
                        {
                            if(noChangeCnt < quickRef) //连续noChangeCnt次没有更新数据延时恢复
                            {
                                noChangeCnt++;
                                if(lastWaitTimeFlg == 3)
                                {
                                    waitTimeFlg = 4;
                                }
                                else if(lastWaitTimeFlg == 0)
                                {
                                    waitTimeFlg = 1;
                                }
                            }
                            else
                            {  
                                if(lastWaitTimeFlg != waitTimeFlg)
                                {
                                    lastWaitTimeFlg = waitTimeFlg;
                                }
                            }
                        }
                        continue;
                    }

                    lastFramPts[displayChn] = pListFrame->pts;

                    if(dealNum == 0)
                    {
                        memcpy(inputFrame1, pListFrame->pBuf, pListFrame->len);
                        inputLen = pListFrame->len;
                    }
                    else
                    {
                        memcpy(inputFrame2, pListFrame->pBuf, pListFrame->len);
                        inputLen2 = pListFrame->len;
                    }

                #if 0
                    char path[64] = {0};
                    sprintf(path,"/nfsroot/wyg/audio_dec_%d.pcm",stream.displayChn);
                    if(stream.displayChn == 0)
                    audio_FILE_Write(path, pListFrame->pBuf, pListFrame->len); 
                    else
                    audio_FILE_Write2(path, pListFrame->pBuf, pListFrame->len); 
                #endif

                    //audio_FILE_Write2("wyg/audio_mix.pcm", pListFrame->pBuf, pListFrame->len); 

                    pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[displayChn].rwLock);


                    pthread_rwlock_wrlock(&pComposeCtl->decComposeBuf[displayChn].rwLock); //加写锁
                    pComposeCtl->userNums[displayChn] += 1; 
                    pthread_rwlock_unlock(&pComposeCtl->decComposeBuf[displayChn].rwLock);

                    dealNum++;
                    
                #if 0
                    if(printCnt++ % 1 == 0)
                    {
                        LOG_PrintInfo("multiplexNums is %d, userNums is %d, curpts=%llu, delpts=%llu\n", pComposeCtl->decComposeBuf[displayChn].multiplexNums, pComposeCtl->userNums[displayChn], vdo_get_time(), pListFrame->pts);
                    }
                #endif
                }
                
            }

            if(dealNum > 0)
            {
                if(totalInput > 1)
                {
                    waitTimeFlg = 3;
                    //LOG_PrintWarn("****two audio enter\n");
                }
                else
                {
                    waitTimeFlg = 0;
                }
    
                lastWaitTimeFlg = waitTimeFlg;
                noChangeCnt = 0;
            }
            else
            {
                break;
            }

            if(dealNum == 1)
            {
                outputFrame = inputFrame1;
                outputLen = inputLen;

                //LOG_PrintError("AMIX_DataComposeThd dealNum=%d, inputLen=%d, curtime=%lld\n",dealNum, inputLen, vdo_get_time()); //time...
            }
            else if(dealNum > 1)
            {     
                //audio_FILE_Write("/extern/audio_dec_1.pcm", inputFrame1, inputLen);                 
                //audio_FILE_Write2("/extern/audio_dec_2.pcm", inputFrame2, inputLen2); 
               
                awi_audio_mixer_process(&cfg_mixer, (short*)inputFrame1, (short*)inputFrame2, AWI_FRAME_SIZE, (short*)algFrame);

                outputFrame = algFrame;
                outputLen = 2*AWI_FRAME_SIZE;
            }

            //audio_FILE_Write3("/extern/audio_mix.pcm", outputFrame, outputLen); 
         
        }

        if(dealNum <= 0)
        {
            continue;
        }

        ///重采样
        if(sampleRate != AUDIO_RESAMPLER_BASE)
        {
            if(lastSampleRate != sampleRate)
            {
                if(mixResampler)
                {
                    speex_resampler_destroy(mixResampler);
                }
                
                mixResampler = speex_resampler_init(1, AUDIO_RESAMPLER_BASE, sampleRate, 1, NULL);
                if(!mixResampler)
                {
                   continue;      
                }

                speex_resampler_set_rate(mixResampler, AUDIO_RESAMPLER_BASE, sampleRate);
                speex_resampler_skip_zeros(mixResampler); 
            }

            //audio_FILE_Write("wyg/audio_mix.pcm", outputFrame, outputLen); 

            //LOG_PrintError("AMIX_DataComposeThd sampleRate=%d, outputFrame=%p, outputLen=%d\n",sampleRate, outputFrame, outputLen); 
            AMIX_DoResampler(mixResampler, sampleRate, outputFrame, &outputLen, algFrame, &algLen);

            outputFrame = algFrame;
            outputLen = algLen;
        }

        ///单声道变成双声道音频流
        if(channelNum == 2)
        {            
            for (int i = 0; i < outputLen; i+=2)
            { 
            	memcpy(dualTrackData + 2*i, outputFrame + i, 2);
            	memcpy(dualTrackData + 2*i + 2, outputFrame + i, 2);
            }

            outputFrame = dualTrackData;
            outputLen *= 2;

            //audio_FILE_Write3("wyg/audio_mix_22.pcm", dualTrackData, 2*pListFrame->len); 
        }
        else if(channelNum == 4)
        { 
            int i = 0; int j = 0;
            for (i = 0, j = 0; j < outputLen; i += 4, j += 2)
            { 
            	memcpy(dualTrackData + 2*i, outputFrame + j, 2);
            	memcpy(dualTrackData + 2*i + 2, outputFrame + j, 2);
            	memcpy(dualTrackData + 2*i + 4, outputFrame + j, 2);
            	memcpy(dualTrackData + 2*i + 6, outputFrame + j, 2);
            }

            outputFrame = dualTrackData;
            outputLen *= channelNum;

            //audio_FILE_Write("wyg/audio_hdmiout.pcm", outputFrame, outputLen); 
        }

        switch(interface)
        {
            case HDMI_OUT: 
            case LINE_OUT:
            case BLUETOOTH_OUT:
            case HORN_OUT:
            {
                /*if(interface == LINE_OUT)
                {
                    int bgmState = 0;
                    getBgmCurtainState(&bgmState);
                    if(bgmState == 0)
                    {  
                        //LOG_PrintWarn("getBgmCurtainState:%d\n", bgmState);
                        break; //BGM优先，场景不输出
                    }
                    else
                    {
                        LOG_PrintWarn("getBgmCurtainState:%d\n", bgmState);
                    }
                }*/
            
                ///音频直接输出,  todo::HDMI_OUT增加是否连接判定
                if(!pAudioOutput)
                {
                    AudioOutDesc outDesc = {0};
                    outDesc.card = 0;
                    if(interface == HDMI_OUT || interface == LINE_OUT)
                    {
                        outDesc.channel=  0;
                    }
                    else
                    {
                        outDesc.channel = interface - LINE_OUT; 
                    }
                    
                    ret = createAudioOutput(&outDesc, &pAudioOutput);
                    if(ret)
                    {
                        LOG_PrintError("createAudioOutput failed\n");
                        break;
                    }

                    if(!pAudioOutput)
                    {
                        break;
                    }
                }
                
                ///采样率或通道数变化时更新输出参数
                if((lastSampleRate != sampleRate) 
                    || (lastChannelNum != channelNum))
                {
                    pAudioOutput->stop(pAudioOutput);
                
                    AudioOutAttr format = {0};  
                    ret = AUDIO_GetOutNode(interface, format.pcAudioNode); //todo
                    if(ret)
                    {
                        LOG_PrintError("AUDIO_GetOutNode failed\n");
                        break;
                    }

                    printf("AO start pcAudioNode=%s, sampleRate=%d, channelNum=%d\n",format.pcAudioNode, sampleRate, channelNum);
                    
            	    format.enSampleFormat = SAMPLE_FMT_S16;               	
                	format.u32SampleRate = sampleRate;
                	format.u32Channels = channelNum;

                	AUDIO_GetOutSamples(sampleRate, &format.u32NbSamples);

                	pAudioOutput->setChnAttr(pAudioOutput, format);
                	
                    pAudioOutput->start(pAudioOutput);

                    lastSampleRate = sampleRate;
                    lastChannelNum = channelNum;
                }

                //AO输出
                pAudioOutput->sendDataToAo(pAudioOutput, outputFrame, outputLen);
                
                break;
            }

            case USBTYPEC_OUT:             
            case SD_OUT:
            case MIRROR_OUT:
            case BYOM_OUT:
            case USBTYPEA_OUT1:
            case USBTYPEA_OUT2:
            case RTSP_MAIN_OUT:
            case RTSP_SUB_OUT1:
            case RTSP_SUB_OUT2:
            case RTSP_SUB_OUT3:
            case RTSP_SUB_OUT4:
            //case RTSP_SUB_OUT5:
            {
                if(lastSampleRate != sampleRate) 
                {
                    lastSampleRate = sampleRate;
                }
                ///通过编码模块输出
                AENC_ctl_t *pEncCtl = audioCtl_g.pEncCtls[interface];
                if (!pEncCtl)
                { 
                    //LOG_PrintError("pEncCtl is NULL, interface=%d!\n",interface); 
                    break;
                }

                //audio_FILE_Write2("wyg/audio_mixout.pcm", outputFrame, outputLen); 

                AudioEncoder audioEncoder = pEncCtl->audioEncoder; 
                audioEncoder.putAudioRawData(&audioEncoder, outputFrame, outputLen, lastFramPts[displayChn]);

            #if 0
                if(printCnt++ % 100 == 0)
                {
                    uint64 runtime = vdo_get_time() - ts;
                    LOG_PrintError("AMIX_DataComposeThd interface=%d, runtime=%llu\n",interface, runtime); 
                }
            #endif
                break;   

            }

            default:
                break;
        }

    }

     return NULL;
}

 int AMIX_InitStreamCompose()
 {
    int ret = 0;
    int  i = 0;
        
#ifdef CONNECT_CORE
    pthread_t thread;
    cpu_set_t cpuset;
    int thread_cpu = 0; // 假设我们想要将线程绑定到第1个核心上
    int thread_num = 0;
#endif
    AMIX_composeCtl_t* pComposeCtl = NULL;
    
    /* 条件变量线程调度唤醒 */
    for(int i = 0; i < MAX_CHN_NUM_AMIX; i++)
    {
        audioCtl_g.sharedData_ai[i] = 0;
        pthread_mutex_init(&audioCtl_g.mutex_ai[i], NULL);
    }

	pthread_cond_init(&audioCtl_g.cond_ai, NULL);
    pthread_mutex_lock(&audioCtl_g.composeMutex);
    

    pComposeCtl = audioCtl_g.pComposeCtl;
    if (pComposeCtl)
    {
        LOG_PrintInfo("audio stream compose has already been created\n");
        goto mutex_unlock;
    }

    pComposeCtl = (AMIX_composeCtl_t *)malloc(sizeof(AMIX_composeCtl_t));
    if (!pComposeCtl)
    {
        LOG_PrintError("There is no enough memory to allocate AMIX_composeCtl_t!\n");
        ret = -1;
        goto mutex_unlock;
    }
    memset(pComposeCtl, 0, sizeof(AMIX_composeCtl_t));

    for(i = 0; i < MAX_CHN_NUM_AMIX; ++i)
    {
        pthread_rwlock_init(&pComposeCtl->decComposeBuf[i].rwLock, NULL);     

        pComposeCtl->newPts[i] = 0;
        pComposeCtl->userNums[i] = 0;


        pthread_mutex_init(&pComposeCtl->mutex_run[i], NULL);
        pthread_cond_init(&pComposeCtl->cond_run[i], NULL);
    }

    audioCtl_g.pComposeCtl = pComposeCtl;
    
#if 1
    /* create send thread */
    ret = pthread_create(&dataPrepareThd_s, NULL, AMIX_DataPrepareThd, pComposeCtl);
    if(ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        ret = -1;
    }

#ifdef CONNECT_CORE
    thread_cpu = thread_num % 3 + 1;
    thread_num ++;
    // 初始化CPU集合
    CPU_ZERO(&cpuset);
    CPU_SET(thread_cpu, &cpuset);
    // 设置线程的CPU亲和性
    pthread_setaffinity_np(dataPrepareThd_s, sizeof(cpu_set_t), &cpuset);
#endif

#ifdef BGM_FUNC
    ret = pthread_create(&lineoutPrepareThd_s, NULL, AMIX_LineoutPrepareThd, pComposeCtl);
    if(ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        ret = -1;
    }
#endif

#ifdef CONNECT_CORE
    /*thread_cpu = thread_num % 3 + 1;
    thread_num ++;
    // 初始化CPU集合
    CPU_ZERO(&cpuset);
    CPU_SET(thread_cpu, &cpuset);
    // 设置线程的CPU亲和性
    pthread_setaffinity_np(lineoutPrepareThd_s, sizeof(cpu_set_t), &cpuset);*/
#endif
#endif

    

#if 1
#ifdef CONNECT_CORE
    struct sched_param sch1;
    sch1.sched_priority = 97;
#endif
    /* create send thread */    
    // for(i = 0; i < AMIX_OUT_NUM -1; ++i)
    for(i = 0; i < AMIX_OUT_NUM; ++i)
    {
        if(i == LINE_OUT)
        {
            continue;
        }

        if(i == RTSP_SUB_OUT1 || i == RTSP_SUB_OUT2 || i == RTSP_SUB_OUT3 || i == RTSP_SUB_OUT4 ||
            i == RTSP_SUB_OUT5 || i == BLUETOOTH_OUT || i == HORN_OUT){
            continue;
        }

        StreamOutInterface *pInterface = malloc(sizeof(*pInterface));
        if(!pInterface)
        {
            LOG_PrintError("malloc failed\n");
            continue;
        }

        *pInterface = i;
#ifdef CONNECT_CORE
        thread_cpu = thread_num % 3 + 1;
        thread_num++;
        // 初始化CPU集合
        CPU_ZERO(&cpuset);
        CPU_SET(thread_cpu, &cpuset);
#endif
        ret = pthread_create(&dataComposeThd_s[i], NULL, AMIX_DataComposeThd, (void*)pInterface);
        if(ret)
        {
            LOG_PrintError("can't create thread: %s\n", strerror(ret));
            ret = -1;
        }

#ifdef CONNECT_CORE
        // 设置线程的CPU亲和性
        //pthread_setaffinity_np(dataComposeThd_s[i], sizeof(cpu_set_t), &cpuset);
        //pthread_setschedparam(dataComposeThd_s[i], SCHED_RR, &sch1);
        //sch1.sched_priority = 97;
        //pthread_setschedparam(dataComposeThd_s[i], SCHED_RR, &sch1);
        //}
#endif        
    }

#ifdef BGM_FUNC
    ret = pthread_create(&lineoutThd_s, NULL, AMIX_LineoutDealThd, NULL);
    if(ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        ret = -1;
    }
#endif
    
    pthread_create(&composeCheckThd_s,NULL,AMIX_ComposeCheckThd,NULL);

#ifdef CONNECT_CORE
    /*
    thread_cpu = thread_num % 3 + 1;
    thread_num ++;
    // 初始化CPU集合
    CPU_ZERO(&cpuset);
    CPU_SET(thread_cpu, &cpuset);
    // 设置线程的CPU亲和性
    pthread_setaffinity_np(lineoutThd_s, sizeof(cpu_set_t), &cpuset);
*/
#endif

#endif
    
    LOG_PrintInfo("initStreamComposesuccessfully!\n");


mutex_unlock:
    pthread_mutex_unlock(&audioCtl_g.composeMutex);


    return ret;
 }


